package com.ruoyi.web.controller.file;// 导入所需的库和包
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.SecurityUtils;
import org.apache.commons.io.IOUtils; // 用于IO操作的工具类
import org.springframework.http.HttpStatus; // HTTP状态码枚举
import org.springframework.http.ResponseEntity; // 用于封装HTTP响应的类
import org.springframework.util.StringUtils; // 字符串工具类（虽然在这段代码中没有使用）
import org.springframework.web.bind.annotation.*; // 用于定义Web接口的注解
import org.springframework.web.multipart.MultipartFile; // 用于处理文件上传的类

import javax.servlet.http.HttpServletRequest;
import java.io.*; // IO操作相关的类
import java.nio.file.*; // 高级文件操作相关的类（虽然在这段代码中没有使用）
import java.util.*; // Java集合框架
import java.util.concurrent.ConcurrentHashMap; // 线程安全的HashMap实现


// 使用@RestController注解，表示这是一个Spring MVC的控制器，返回的视图名会被解析为JSON或XML等格式
@RestController
// 使用@RequestMapping注解定义基础路径
@RequestMapping("/shareDive/upload")
public class FileUploadController {

    // 定义上传文件的目录常量

    private String UPLOAD_DIR(){
        return  RuoYiConfig.getProfile() +  System.getProperty("file.separator") + "shareDive" + System.getProperty("file.separator") + SecurityUtils.getLoginUser().getUserId() + System.getProperty("file.separator");
    }

    // 使用ConcurrentHashMap存储上传会话，确保线程安全
    private final Map<String, Integer> uploadSessions = new ConcurrentHashMap<>();
    private final Map<String, String> fileNameSession = new ConcurrentHashMap<>();

    // 发起上传的接口，用于初始化上传会话并返回文件ID
    @RequestMapping(value = "/initiate",method = RequestMethod.POST)
    public R<Map<String, String>> initiateUpload(HttpServletRequest request) {

        //检查是否有重名文件
        String fileName = request.getParameter("fileName");
        File tempFile = new File(UPLOAD_DIR());
        if(!tempFile.isDirectory()){
            tempFile.mkdirs();
        }
        File[] fileArr = tempFile.listFiles();
        for(int i = 0 ; i < fileArr.length ; i++){
            if(fileName.equals(fileArr[i].getName())){
                return R.fail("发现重名文件，请修改文件名称");
            }
        }



        // 生成唯一的文件ID
        String fileId = UUID.randomUUID().toString();
        // 初始化文件块的计数器为0
        uploadSessions.put(fileId, 0);
        // 初始化文件名称
        fileNameSession.put(fileId, fileName);

        // 创建上传目录（如果不存在）
        File uploadDir = new File(UPLOAD_DIR() + fileId);
        uploadDir.mkdirs();

        // 准备响应数据
        Map<String, String> response = new HashMap<>();
        response.put("fileId", fileId);
        // 返回包含文件ID的响应
        return R.ok(response);
    }

    // 上传文件块的接口
    @PostMapping("/chunk")
    public R uploadChunk(@RequestParam("chunk") MultipartFile chunk,
                                            @RequestParam("fileId") String fileId,
                                            @RequestParam("chunkNumber") int chunkNumber,
                                            @RequestParam("totalChunks") int totalChunks) throws IOException {
        // 检查文件ID是否存在于会话中
        if (!uploadSessions.containsKey(fileId)) {
            return R.fail("not fileId:" + fileId);
        }

        // 获取当前会话中的块计数器，并检查是否与请求的块编号匹配
        int currentChunk = uploadSessions.get(fileId) + 1;
        if (currentChunk != chunkNumber) {
            return R.fail("Chunk num error, need" + currentChunk + ", find" + chunkNumber);
        }

        Path path = new File(UPLOAD_DIR() + fileId + "/chunk_" + chunkNumber).toPath();

        // 将文件块保存到磁盘
        try (OutputStream os = Files.newOutputStream(path)) {
            System.out.println(path.toAbsolutePath().toString());
            IOUtils.copy(chunk.getInputStream(), os);
            // 更新会话中的块计数器
            uploadSessions.put(fileId, currentChunk);
        } catch (IOException e) {
            // 打印异常堆栈（生产环境中应使用日志记录）
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
        // 返回成功响应
        return R.ok();
    }

    // 完成上传的接口
    //@Anonymous
    @PostMapping("/complete/{fileId}")
    public R completeUpload(@PathVariable String fileId) {
        // 检查会话状态，确保所有块都已上传
        System.out.println(!uploadSessions.containsKey(fileId));
        System.out.println(uploadSessions.get(fileId));
        System.out.println(uploadSessions.getOrDefault(fileId, 0) + 1);
        if (!uploadSessions.containsKey(fileId) ) {
            return R.fail("not fileId:" + fileId);
        }

        try {
            // 获取并排序所有文件块
            List<File> chunks = Arrays.asList(Objects.requireNonNull(new File(UPLOAD_DIR() + fileId).listFiles((dir, name) -> name.startsWith("chunk_"))));
            chunks.sort(Comparator.comparingInt(file -> Integer.parseInt(file.getName().split("_")[1])));

            // 创建合并后的文件
            File mergedFile = new File(UPLOAD_DIR() + fileNameSession.get(fileId));
            try (OutputStream os = Files.newOutputStream(mergedFile.toPath())) {
                // 逐个读取文件块并写入合并文件
                for (File chunk : chunks) {
                    try (InputStream is = Files.newInputStream(chunk.toPath())) {
                        IOUtils.copy(is, os);
                    }
                    // 删除已合并的文件块
                    chunk.delete();
                }
            }

            // 清理会话和临时目录
            uploadSessions.remove(fileId);
            new File(UPLOAD_DIR() + fileId).delete();

        } catch (IOException e) {
            // 打印异常堆栈（生产环境中应使用日志记录）
            e.printStackTrace();
            return R.fail(e.getMessage());
        }

        // 返回成功响应
        return R.ok();
    }
}